package com.middleware.mvc.servlet;

import com.middleware.mvc.annotations.Controller;
import com.middleware.mvc.context.WebApplicationContext;
import com.middleware.mvc.handleMapping.HandlerMapping;
import com.middleware.mvc.handler.InvocationHandler;
import com.middleware.mvc.handlerAdapter.HandlerAdapter;
import com.middleware.mvc.handlerAdapter.HandlerAdapterScan;
import com.middleware.mvc.loaders.AppPropertiesLoader;
import com.middleware.spring.context.ApplicationContext;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.File;
import java.io.IOException;
import java.lang.annotation.Annotation;
import java.net.URL;
import java.util.ArrayList;
import java.util.List;

public class DispatcherServlet extends HttpServlet {

    private static final Logger log = LoggerFactory.getLogger(DispatcherServlet.class);

    WebApplicationContext webApplicationContext = null;

    HandlerMapping handlerMapping = null;

    List<HandlerAdapter> handlerAdapters = null;


    @Override
    public void init() throws ServletException {
        String webPath = AppPropertiesLoader.getProperty("simple.mvc.scan");

        //从servlet 上下文中获取参数
        ServletContext servletContext = this.getServletContext();
        ApplicationContext applicationContext = (ApplicationContext)servletContext.getAttribute("applicationContext");
        webApplicationContext = new WebApplicationContext(webPath,applicationContext);

        List<Class<?>> classes = scanPackageByAnnotation(webPath, Controller.class);

        handlerMapping = new HandlerMapping();
        handlerMapping.init(classes,webApplicationContext);

        HandlerAdapterScan handlerAdapterScan = new HandlerAdapterScan();
        handlerAdapters = handlerAdapterScan.getHandlerAdapters();


    }

    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        this.doPost(req, resp);
    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {

        StringBuffer requestURL = req.getRequestURL();
        System.out.println("客户端请求路径：" + requestURL);
        // 判断请求路径中是否包含项目名，包含的话使用空字符替换掉
        String path = new String(requestURL).replace("http://" +
                req.getServerName() + ":" + req.getServerPort(), "");
        System.out.println("处理后的客户端请求路径：" + path);
        // 根据处理好的 path 作为条件去map中查找对应的方法
        InvocationHandler handler = handlerMapping.getHandler(path);
        if (handler == null) {
            log.error("未找到对应的方法：{}", path);
            resp.sendError(404);
            return;
        }
        HandlerAdapter handlerAdapter = getHandlerAdapter(handler);
        try {
            handlerAdapter.handle(req, resp, handler);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }


    protected List<Class<?>> scanPackageByAnnotation(String path, Class<? extends Annotation> annotation) {
        List<Class<?>> beanClassList = new ArrayList<>();
        // 获取类加载器
        ClassLoader classLoader = ApplicationContext.class.getClassLoader();

        path = path.replace(".", "/");

        URL resource = classLoader.getResource(path);
        if (resource == null) {
            log.warn("包路径不存在: {}", path);
            return beanClassList;
        }

        File file = new File(resource.getFile());
        // 递归扫描目录
        scanDirectory(file, path.replace("/", "."), beanClassList, classLoader, annotation);

        return beanClassList;
    }

    /**
     * 递归扫描目录中的类文件
     * @param directory 要扫描的目录
     * @param currentPackage 当前包名
     * @param beanClassList 存储Bean类的列表
     * @param classLoader 类加载器
     */
    protected void scanDirectory(File directory, String currentPackage,
                                 List<Class<?>> beanClassList, ClassLoader classLoader, Class<? extends Annotation> annotation) {
        if (!directory.exists() || !directory.isDirectory()) {
            return;
        }

        File[] files = directory.listFiles();
        if (files == null) {
            return;
        }

        for (File f : files) {
            if (f.isDirectory()) {
                // 递归扫描子目录，更新包名
                String subPackage = currentPackage + "." + f.getName();
                scanDirectory(f, subPackage, beanClassList, classLoader, annotation);
            } else if (f.getName().endsWith(".class")) {
                // 处理类文件
                processClassFile(f, currentPackage, beanClassList, classLoader, annotation);
            }
        }
    }

    /**
     * 处理类文件并检查注解
     */
    protected void processClassFile(File classFile, String currentPackage,
                                    List<Class<?>> beanClassList, ClassLoader classLoader, Class<? extends Annotation> annotation) {
        try {
            // 获取简单类名（去掉.class后缀）
            String className = classFile.getName().replace(".class", "");
            // 构建完整类名
            String fullClassName = currentPackage + "." + className;

            // 排除内部类
            if (className.contains("$")) {
                return;
            }

            Class<?> clazz = classLoader.loadClass(fullClassName);
            if (clazz.isAnnotationPresent(annotation) ) {
                beanClassList.add(clazz);
            }
        } catch (ClassNotFoundException e) {
            log.error("加载类失败: {}", classFile.getName(), e);
        } catch (NoClassDefFoundError e) {
            log.warn("类定义不完整: {}, 错误: {}", classFile.getName(), e.getMessage());
        }
    }

    private HandlerAdapter getHandlerAdapter(Object handler) {
        for (HandlerAdapter handlerAdapter : handlerAdapters) {
            if (handlerAdapter.supports(handler)) {
                return handlerAdapter;
            }
        }
        return null;
    }


}
